package tp.pr4;

import java.util.Scanner;

import javax.swing.JOptionPane;


import tp.pr4.gui.*;
import tp.pr4.instructions.Instruction;
import tp.pr4.instructions.exceptions.InstructionExecutionException;
import tp.pr4.items.ItemContainer;
/**
 * 
 * @author Carlos Bermúdez y Mario de Benito
 *
 */
public class RobotEngine {	
	//--
	//private Direction direction;
	//private Street[] cityMap;
	//private City city;
	//private Place currentPlace;	
	private NavigationModule navCon;
	private boolean quit;
	//--
	//--
	private int fuel;
	private int recycledMaterial;
	private ItemContainer items;
	private MainWindow main;	
	private boolean swingInterface;
	
	private Instruction lastInstruction;
	//--
	//private NavigationPanel navPan;
	//private RobotPanel rbtPan;
	
	/**
	 * Creates the robot engine in an initial place, facing at an initial direction and with a city map
	 * @param initialPlace
	 * @param direction
	 * @param cityMap
	 */
	/*public RobotEngine(Place initialPlace, Direction direction, Street[] cityMap){		
		this.direction = direction;
		this.cityMap = cityMap;
		this.currentPlace = initialPlace;
		this.items = new ItemContainer();
		this.fuel = 50;
	}	*/
	public RobotEngine(City cityMap, Place initialPlace, Direction dir){
		//this.cityMap = cityMap.cityMap;		
		this.items = new ItemContainer();
		this.fuel = 100;
		this.navCon = new NavigationModule(cityMap, initialPlace);
		this.navCon.initHeading(dir);
		this.quit = false;
		
		
	}	
	
	/**
	 * Starts the engine
	 */
	void startEngine(){	
		
		Scanner reader = new Scanner(System.in); //scanner a usar durante todo el bucle
		
		Instruction instructionGiven = null;//instruccion a usar durnte todo el bucle
		Interpreter interp = new Interpreter(); //interprete a usar durante todo el bucle
		
		//muestra localización inicial y dirección inicial
		System.out.println(this.navCon.showLocation() + 
				Main.LINE_SEPARATOR + 
				"WALL·E is looking at direction "+this.navCon.getCurrentHeading().name() +				
				Main.LINE_SEPARATOR + 
				this.getStatus());				
		
		if(swingInterface){
			main.setVisible(true);
		}
		
		//el bucle funciona hasta que se llegue a la nave o se introduzca la acción QUIT
		while(!(this.navCon.atSpaceship() || this.quit || this.fuel <=0)){ //comprueba que no ha llegado a la nave y que la instruccion no es la de salir	
			//saca por pantalla 'WALL·E>'
			try{
				instructionGiven = this.getInstruction(reader, interp);//recoge de la consola la instrucción del usuario y la convierte en un objeto instruction
				communicateRobot(instructionGiven);				
			}catch(Exception e){
				//System.out.println("WALL·E says: I do not understand. Please repeat");	
			}				
			
		}//fin del bucle principal
		
		//FINAL DEL JUEGO
		if(this.navCon.atSpaceship()){//si ha llegado a la nave
			System.out.println("WALL·E says: I am at my spaceship. Bye bye");
			
		}
	}
	/**
	 * Sets the the swîngInterface
	 */
	public void setSwingInterface(boolean b){
		this.swingInterface = b;
	}
	
	/**
	 * Sets the navigation panel for the robot
	 */
	/*public void setNavigationPanel(NavigationPanel navPan){
		this.navPan = navPan;
	}*/	
	/**
	 * Sets the robot panel for the robot
	 */
	/*public void setRobotPanel(RobotPanel rbtPan){
		this.rbtPan = rbtPan;
	}*/
	/**
	 * Sets the main window for the robot
	 */
	public void setGUIWindow(MainWindow main){
		this.main = main;
	}
	
	
	/**
	 * Toma una instrucción de consola y usa el intérprete para convertirla en objeto
	 * @param sc
	 * @param interp
	 * @return
	 */
	private Instruction getInstruction(Scanner sc, Interpreter interp){		
		System.out.print(prompt());
		String ins = sc.nextLine();
		try{
			return Interpreter.parse(ins);
		}catch (Exception e){			
			return null;
		}
	}
	/**
	 * Imprime por pantalla 'WALL·E'
	 */
	private String prompt(){
		return "WALL·E> ";
	}
	/**
	 * 	Adds an amount of fuel to the robot (it can be negative)
	 * @param fuel
	 */
	public void addFuel(int fuel) {
		this.fuel = this.fuel + fuel;
	}
	/**
	 * Increases the amount of recycled material of the robot 
	 * @param weight
	 */
	public void addRecycledMaterial(int weight){
		this.recycledMaterial = this.recycledMaterial + weight;
	} 
	/**
	 * 	Returns the current fuel level of the robot.
	 * @return
	 */
	public int getFuel(){
		return this.fuel;
	} 
	/**
	 * Returns the current weight of recycled material that the robot carries. This method is mandatory FOR TESTING PURPOSES
	 * @return
	 */
	public int getRecycledMaterial(){
		return this.recycledMaterial;
	} 
	/**
	 * Returns the street opposite the robot
	 * @return
	 */
	
	/**
	 * Returns fuel & recycled material status string
	 * @return
	 */
	public String getStatus(){
		return "      * My power is "+this.getFuel()+Main.LINE_SEPARATOR+
			   "      * My reclycled material is "+this.getRecycledMaterial();
	}
	/**
	 * Returns the items array
	 * @return
	 */
	public ItemContainer getInventory(){
		return this.items;
	}
	/**
	 * sets a new value for the fuel
	 * @param fuel
	 */
	public void setFuel(int fuel){
		this.fuel = fuel;
	}
	/**
	 * flags the robot to quit the game 
	 */
	public void requestQuit(){
		this.quit = true;
	}
	/**
	 * prints the interpreter help
	 */
	public void requestHelp(){
		System.out.println(Interpreter.interpreterHelp());
	}
	/**
	 * returns the robot's navigationmodule
	 * @return
	 */
	public NavigationModule getNavigationModule(){
		return this.navCon;
	}
	/**
	 * configures the context of the instruction and executes it
	 * @param ins
	 */
	public void communicateRobot(Instruction ins){	
		if(ins.isUndoAble()) this.lastInstruction = ins;
		ins.configureContext(this, this.navCon, this.getInventory());
		if(this.getFuel() > 0){
			try{
				ins.execute();
				if(main != null){			
					main.refresh();
				}
			}catch (InstructionExecutionException e){
				if(main != null){				
					JOptionPane.showMessageDialog (null, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
		}else{
			if(main != null){
				main.gameOver();				
			}
			requestQuit();
			
		}
	}
	/**
	 * prints current robot status
	 */
	public void printRobotState(){
		System.out.println(this.getStatus());
	}
	
	/**
	 * gets the last instruction object
	 */
	public Instruction getLastInstruction(){
		return this.lastInstruction;
	}
	/**
	 * returns the reference to the main window
	 * @return
	 */
	public MainWindow getMainWindow(){
		return this.main;
	}
}
